package com.ruoyi.framework.interceptor;

import com.ruoyi.common.annotation.IgnoreAuth;
import com.ruoyi.common.constant.BuConstants;
import com.ruoyi.common.core.domain.ApiResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.InterceptorUtil;
import com.ruoyi.common.utils.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 * （过滤前-拦截前-action执行-拦截后-过滤后）
 * interceptor拦截器（对过滤器放行的接口进行拦截，判断登陆以及用户注入等操作）
 * 此拦截器作用方式是判断请求头里面的token是否过期或者是否有token数据判断出是否需要拦截进行跳转到登录重新登录
 * @author yangz
 * @email 17866232944@163.com
 */
@Component
public class AuthInterceptor implements HandlerInterceptor {

    private static final Logger log = LoggerFactory.getLogger(AuthInterceptor.class);


    @Autowired
    private RedisCache redisCache;

    public static final String LOGIN_USER_KEY = "LOGIN_USER_TOKEN";
    public static final String LOGIN_TOKEN_KEY="token";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //支持跨域请求
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with,X-Nideshop-Token,X-URL-PATH");
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));

        log.info("进入AuthInterceptor层拦截器");

        // 如果不是映射到方法，直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        // 检查是否有IgnoreAuth注解
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        IgnoreAuth ignoreAuth = handlerMethod.getMethodAnnotation(IgnoreAuth.class);
        // 有IgnoreAuth注解，直接通过
        if (ignoreAuth != null) {
            return true;
        }


        //从header中获取token
        String token=request.getHeader(LOGIN_TOKEN_KEY);
        if (StringUtils.isBlank(token)) {
            token = request.getParameter(LOGIN_TOKEN_KEY);
        }
        if (StringUtils.isEmpty(token)) {
            // 判断特殊接口比如initIndex接口
            String requestURI = request.getRequestURI();
            if (InterceptorUtil.isInWhiteList(requestURI)){
                //如果是白名单里面的接口，直接放心
                return true;
            }
            responseError(response, "请先登录");
            return false;
        }

        //查询token信息
        Object userInfoObject= redisCache.getCacheObject(BuConstants.MINITOKEN+token);
        if (StringUtils.isNull(userInfoObject)){
            // 判断特殊接口比如initIndex接口
            String requestURI = request.getRequestURI();
            if (InterceptorUtil.isInWhiteList(requestURI)){
                //如果是白名单里面的接口，直接放心
                return true;
            }
            //用户未登陆
            responseError(response, "登录已过期，请重新登录");
            return false;
        }else {
            //设置token到request里，后续根据token，获取用户信息
            request.setAttribute(LOGIN_USER_KEY, token);
        }
        // token有效，放行
        return true;
    }

    private void responseError(HttpServletResponse response, String message) throws Exception {
        response.setContentType("application/json; charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write(new ObjectMapper().writeValueAsString(ApiResult.error(ApiResult.EnumCode.NOT_AUTHORITY,message)));
        writer.flush();
        writer.close();
    }
}